package cate.game.framework.advanced;

import cate.game.framework.Attributes;

import java.util.StringJoiner;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.Long.SIZE;

public class AdvancedLongAttributes implements Attributes<Integer, Long> {
    private long attributes;

    public static AdvancedLongAttributes of(long attributes) {
        return new AdvancedLongAttributes(attributes);
    }

    public AdvancedLongAttributes() {
        this(0L);
    }

    public AdvancedLongAttributes(long attributes) {
        this.attributes = attributes;
    }

    @Override
    public boolean hasAttribute(Integer flag) {
        checkFlagOrThrow(flag);
        long flagValue = getFlagValue(flag);
        return (attributes & flagValue) == flagValue;
    }

    public void setAttribute(Integer flag) {
        checkFlagOrThrow(flag);
        setAttribute(flag, getFlagValue(flag));
    }

    @Override
    public void setAttribute(Integer flag, Long value) {
        checkFlagOrThrow(flag);
        if (!hasAttribute(flag)) {
            attributes |= value;
        }
    }

    @Override
    public void removeAttribute(Integer flag) {
        checkFlagOrThrow(flag);
        attributes &= ~getFlagValue(flag);
    }

    @Override
    public int size() {
        return Long.bitCount(attributes);
    }

    @Override
    public void clear() {
        this.attributes = 0L;
    }

    private void checkFlagOrThrow(Integer flag) {
        checkArgument(flag >= 1, "flag 不能小于 1");
        checkArgument(flag <= SIZE, "flag 不能大于 " + SIZE);
    }

    private long getFlagValue(Integer flag) {
        return 1L << (flag - 1);
    }

    @Override
    public String toString() {
        return new StringJoiner(", ", AdvancedLongAttributes.class.getSimpleName() + "[", "]")
                .add("attributes=" + Long.toBinaryString(attributes))
                .add("size=" + size())
                .toString();
    }
}
